package client.domain;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

/**
 * User: nbarrios
 * Date: Nov 19, 2009
 */
public class Chart{

	private static final String URL_GOOGLE_CHART_SERVER = "http://chart.apis.google.com/chart?";

	private static final String URL_PARAMETERS_ASIGNATOR = "=";
	private static final String URL_PARAMETERS_SEPARATOR = "&";
	private static final String URL_PARAMETERS_DATA_SEPARATOR_COMMA = ",";
	private static final String URL_PARAMETERS_LABELS_SEPARATOR_PIPE = "|";

	private static final String OMMIT_DATA_VALUE_FOR_DATA_ENCODING_SIMPLE = "_";
	private static final String OMMIT_DATA_VALUE_FOR_DATA_ENCODING_TEXT = "-1";

	//	Name of charts
	public static final String CHART_NAME_PIE_2D = "Pie 2d";
	public static final String CHART_NAME_PIE_3D = "Pie 3d";
	public static final String CHART_NAME_LINE_CHART = "Line Chart";
	public static final String CHART_NAME_SOME_LINES_CHART = "Various Lines Chart";
	public static final String CHART_NAME_WORD_GRAPH = "Word Graph";
	public static final String CHART_NAME_HORIZONTAL_BAR = "Horizontal Bar";
	public static final String CHART_NAME_VERTICAL_BAR = "Vertical Bar";
	public static final String CHART_NAME_VENN = "Venn";
	public static final String CHART_NAME_POINTS = "Points";
	public static final String CHART_NAME_RADAR_STRAIGHT_LINES = "Radar Straight Lines";
	public static final String CHART_NAME_RADAR_CURVED_LINES = "Radar Curved Lines";
	public static final String CHART_NAME_MAP = "Map";
	public static final String CHART_NAME_GOOGLE_O_METE = "Google-o-mete";

	//	URL parameters
	public static final String CHART_PARAMETER_SIZE = "chs";
	public static final String CHART_PARAMETER_TYPE = "cht";
	public static final String CHART_PARAMETER_LABELS = "chl";
	public static final String CHART_PARAMETER_DATA = "chd";
	public static final String CHART_PARAMETER_DATA_COLOURS = "chco";
	public static final String CHART_PARAMETER_BAR_FORMATTING = "chbh";
	public static final String CHART_PARAMETER_BASE_LINE_POSITION = "chp";
	public static final String CHART_PARAMETER_LINE_STYLE = "chls";
	public static final String CHART_PARAMETER_GRID_STYLE = "chg";
	public static final String CHART_PARAMETER_MAP_ZONE = "chtm";
	public static final String CHART_PARAMETER_MAP_SELECTED_COUNTRIES = "chld";

	public static final String CHART_PARAMETER_TITLE = "chtt";
	public static final String CHART_PARAMETER_TITLE_STYLE = "chts";

	public static final String CHART_PARAMETER_LEYEND = "chdl";
	public static final String CHART_PARAMETER_LEYEND_POSITION = "chdlp";

	//	Type of charts
	public static final String CHART_PARAMETER_TYPE_VALUE_PIE_2D = "p";
	public static final String CHART_PARAMETER_TYPE_VALUE_PIE_3D = "p3";
	public static final String CHART_PARAMETER_TYPE_VALUE_LINE_CHART = "lc";
	public static final String CHART_PARAMETER_TYPE_VALUE_SOME_LINES_CHART = "lxy";
	public static final String CHART_PARAMETER_TYPE_VALUE_WORD_GRAPH = "ls";
	public static final String CHART_PARAMETER_TYPE_VALUE_HORIZONTAL_BAR = "bhs";
	public static final String CHART_PARAMETER_TYPE_VALUE_VERTICAL_BAR = "bvs";
	public static final String CHART_PARAMETER_TYPE_VALUE_VENN = "v";
	public static final String CHART_PARAMETER_TYPE_VALUE_POINTS = "s";
	public static final String CHART_PARAMETER_TYPE_VALUE_RADAR_STRAIGHT_LINES = "r";
	public static final String CHART_PARAMETER_TYPE_VALUE_RADAR_CURVED_LINES = "rs";
	public static final String CHART_PARAMETER_TYPE_VALUE_MAP = "t";
	public static final String CHART_PARAMETER_TYPE_VALUE_GOOGLE_O_METE = "gom";

	public static final String CHART_PARAMETER_DATA_TEXT_ENCODING_VALUE_TEXT = "t:";
	public static final String CHART_PARAMETER_DATA_TEXT_ENCODING_VALUE_SIMPLE = "s:";
	public static final String CHART_PARAMETER_DATA_TEXT_ENCODING_VALUE_ENLARGED = "e:";

	//	Possibles zones for a map chart
	public static final String MAP_ZONE_AFRICA = "africa";
	public static final String MAP_ZONE_ASIA = "asia";
	public static final String MAP_ZONE_EUROPE = "europe";
	public static final String MAP_ZONE_WORLD = "world";
	public static final String MAP_ZONE_USA = "usa";
	public static final String MAP_ZONE_MIDDLE_EAST = "middle_east";
	public static final String MAP_ZONE_SOUTH_AMERICA = "south_america";


	//  Attributes
	private String dataTextEncoding;					//CHART_PARAMETER_DATA

	//	Parameters of: CHART_PARAMETER_SIZE
	private Integer width;
	private Integer height;

	private String type;								//CHART_PARAMETER_TYPE
	private Collection<ChartProperty> properties;		//CHART_PARAMETER_LABELS & CHART_PARAMETER_DATA & CHART_PARAMETER_DATA_COLOURS

	private String title;								//CHART_PARAMETER_TITLE

	//	Parameters of: CHART_PARAMETER_TITLE_STYLE
	private String titleColor;
	private Integer titleFontSize;

	private Map leyends;								//CHART_PARAMETER_LEYEND
	private Integer leyendsPosition;					//CHART_PARAMETER_LEYEND_POSITION

	//	Parameters of: CHART_PARAMETER_BAR_FORMATTING
	private Integer barWidth;
	private Integer barsOfSameDataGroupSpacing;
	private Integer barsOfDifferentDataGroupSpacing;

	private Float baseLinePosition;						//CHART_PARAMETER_BASE_LINE_POSITION

	//	Parameters of:	CHART_PARAMETER_LINE_STYLE
	private Integer lineWidth;
	private Integer lineLength;
	private Integer lineSpacing;

	//	Parameters of:	CHART_PARAMETER_GRID_STYLE
	private Integer gridCellHeight;
	private Integer gridCellWidth;
	private Integer gridLineLength;
	private Integer gridLinesSpacing;

	private String mapZone;								//CHART_PARAMETER_MAP_ZONE


	/**
	 * @param property	A property to show in the chart.
	 */
	public void addProperty(ChartProperty property){
		if(this.properties==null)
			this.properties = new ArrayList<ChartProperty>();

        this.properties.add(property);
	}

	/**
	 * <p>Parse the parameters and makes the URL.</p>
	 * <p><b>Important:</b> Before calling this method, the Chart object must be assigned the following attributes:</p>
	 * 	<p>	chartType	<br>
	 * 	chartWidth	    <br>
	 * 	chartHeight	    <br>
	 * 	dataTextEncoding<br>
	 * 	properties	</p>
	 * 
	 * @return	The parsed {@link java.lang.String} URL ready to do: "<b>Image img = new Image(this.create());</b>" and generate the chart image.
	 */
	public String create(){
		StringBuffer url = new StringBuffer("");
		url.append(URL_GOOGLE_CHART_SERVER);
		try{
			StringBuffer data = new StringBuffer(CHART_PARAMETER_DATA);
			data.append(URL_PARAMETERS_ASIGNATOR).append(this.dataTextEncoding);

			StringBuffer labels = new StringBuffer(CHART_PARAMETER_LABELS);
			labels.append(URL_PARAMETERS_ASIGNATOR);

			StringBuffer colours = new StringBuffer(CHART_PARAMETER_DATA_COLOURS);
			colours.append(URL_PARAMETERS_ASIGNATOR);

			boolean isColoursSetted = true
					, isLabelsSetted = true;

			if(properties!=null)
				for (ChartProperty property : properties) {
					//	Works with the data
					data.append(property.getData()).append(URL_PARAMETERS_DATA_SEPARATOR_COMMA);

					//	Works with the labels
					if(isLabelsSetted && property.getLabel()!=null)
						labels.append(property.getLabel()).append(URL_PARAMETERS_LABELS_SEPARATOR_PIPE);
					else
						isLabelsSetted = false;

					//	Works with the colours for the data
					if(isColoursSetted && property.getColour()!=null)
						colours.append(property.getColour()).append(URL_PARAMETERS_DATA_SEPARATOR_COMMA);
					else
						isColoursSetted = false;
				}
			else{
				//	Verify which value will be assigned as ommited value
				if(this.dataTextEncoding.equals(CHART_PARAMETER_DATA_TEXT_ENCODING_VALUE_SIMPLE))
						data.append(OMMIT_DATA_VALUE_FOR_DATA_ENCODING_SIMPLE).append(URL_PARAMETERS_DATA_SEPARATOR_COMMA);

				else if(this.dataTextEncoding.endsWith(CHART_PARAMETER_DATA_TEXT_ENCODING_VALUE_TEXT))
					data.append(OMMIT_DATA_VALUE_FOR_DATA_ENCODING_TEXT).append(URL_PARAMETERS_DATA_SEPARATOR_COMMA);

				isColoursSetted = false;
				isLabelsSetted = false;
			}

			//	Remove the last character wich is an unnecessary comma(,)/pipe(|) 
			data.deleteCharAt(data.length()-1);
			if(isLabelsSetted)
				labels.deleteCharAt(labels.length()-1);
			if(isColoursSetted)
				colours.deleteCharAt(colours.length()-1);


			//	Required parameters.
			url.append(CHART_PARAMETER_TYPE).append(URL_PARAMETERS_ASIGNATOR).append(this.type)
					.append(URL_PARAMETERS_SEPARATOR).append(CHART_PARAMETER_SIZE).append(URL_PARAMETERS_ASIGNATOR).append(this.width).append("x").append(this.height)
					.append(URL_PARAMETERS_SEPARATOR).append(data.toString());


			//	Maps Required parameters
			if(this.type.equals(CHART_PARAMETER_TYPE_VALUE_MAP))
				url.append(URL_PARAMETERS_SEPARATOR).append(CHART_PARAMETER_MAP_ZONE).append(URL_PARAMETERS_ASIGNATOR).append(this.mapZone);


			//	Optional parameters.
			if(isLabelsSetted)
				url.append(URL_PARAMETERS_SEPARATOR).append(labels.toString());

			if(isColoursSetted)
				url.append(URL_PARAMETERS_SEPARATOR).append(colours.toString());

			//  TODO:   Terminar este metodo para todos los parametros!!
		}
		catch(Exception e){
			e.printStackTrace();
			System.err.println("Check if the object has got assigned the required attributes.");
			throw new RuntimeException();
		}

		return url.toString();
	}

	// Constructor
	/**
	 * Creates an empty chart.
	 * @param chartType	The type of chart to create.
	 * <p><b>Important:</b>	It must be one of theese ones			  </p><br>
	 * <p>	Chart.CHART_PARAMETER_TYPE_VALUE_PIE_2D					  <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_PIE_3D                   <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_LINE_CHART               <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_SOME_LINES_CHART         <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_WORD_GRAPH               <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_HORIZONTAL_BAR           <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_VERTICAL_BAR             <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_VENN                     <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_POINTS                   <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_RADAR_STRAIGHT_LINES     <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_RADAR_CURVED_LINES       <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_MAP                      <br>
	 *		Chart.CHART_PARAMETER_TYPE_VALUE_GOOGLE_O_METE            </p>
	 */
	public Chart(String chartType) {
		super();
		this.type = chartType;
	}

	//  Getters & Setters
	/**
	 * @return	The chart width.
	 */
	public Integer getWidth() {		return width;		}

	/**
	 * @return	The chart height.
	 */
	public Integer getHeight() {		return height;		}

	/**
	 * @return	The chart type.
	 */
	public String getType() {		return type;		}

	/**
	 * @return	The chart title
	 */
	public String getTitle() {		return title;		}

	/**
	 * @return	The color of the title in RRGGBB format.
	 */
	public String getTitleColor() {		return titleColor;		}

	/**
	 * @return	The title font size in pixels.
	 */
	public Integer getTitleFontSize() { 	return titleFontSize;		}

	/**
	 * @return Leyends of each data group of the graph.
	 */
	public Map getLeyends() {	return leyends;		}

	/**
	 * @return	The position of the leyends inside the graph.
	 */
	public Integer getLeyendsPosition() {	return leyendsPosition;		}

	/**
	 * @return The bar width in pixels in a horizontal/vertical bar chart.
	 */
	public Integer getBarWidth() {		return barWidth;		}

	/**
	 * @return	The bars spacing in pixels between bars of same data group in a horizontal/vertical bar chart.
	 */
	public Integer getBarsOfSameDataGroupSpacing() {	return barsOfSameDataGroupSpacing;		}

	/**
	 * @return	The bars spacing in pixels between bars of different data group in a horizontal/vertical bar chart.
	 */
	public Integer getBarsOfDifferentDataGroupSpacing() {		return barsOfDifferentDataGroupSpacing;		}

	/**
	 * @return	The position of the base line in a horizontal/vertical bar chart.
	 */
	public Float getBaseLinePosition() {	return baseLinePosition;	}

	/**
	 * @return	The width in pixels of the lines in a line chart.
	 */
	public Integer getLineWidth() {		return lineWidth;		}

	/**
	 * @return	The length in pixels of a line segment in a line chart.
	 */
	public Integer getLineLength() {	return lineLength;		}

	/**
	 * @return	The space in pixels between line segments in a line chart.
	 */
	public Integer getLineSpacing() {	return lineSpacing;		}

	/**
	 * @return	The height of the grid's cells.
	 */
	public Integer getGridCellHeight() {	return gridCellHeight;	}

	/**
	 * @return	The width of the grid's cells.
	 */
	public Integer getGridCellWidth() {		return gridCellWidth;	}

	/**
	 * @return	The lines length in pixels of the grid.
	 */
	public Integer getGridLineLength() {	return gridLineLength;		}

	/**
	 * @return	The space in pixels between the lines of the grid.
	 */
	public Integer getGridLinesSpacing() {	return gridLinesSpacing;	}

	/**
	 * @return	A Collection with the properties that the chart will show.
	 */
	public Collection<ChartProperty> getProperties() {	return properties;	}

	/**
	 * @return	The data text encoding.
	 */
	public String getDataTextEncoding() {	return dataTextEncoding;	}

	/**
	 * @return	The map zone to visualize on the chart.
	 */
	public String getMapZone() {	return mapZone;		}

	/**
	 * @param width	The chart width.
	 */
	public void setWidth(Integer width) {		this.width = width;	}

	/**
	 * @param height	The chart height.
	 */
	public void setHeight(Integer height) {	this.height = height;		}

	/**
	 * @param chartType	The chart type.
	 */
	public void setType(String chartType) {	this.type = chartType;		}

	/**
	 * @param title	The chart title.
	 */
	public void setTitle(String title) {	this.title = title;		}

	/**
	 * @param titleColor	The color of the title in RRGGBB format. Eg. "AA45CC".
	 */
	public void setTitleColor(String titleColor) {		this.titleColor = titleColor;	}

	/**
	 * @param titleFontSize	The title font size in pixels.
	 */
	public void setTitleFontSize(Integer titleFontSize) {	this.titleFontSize = titleFontSize;		}

	/**
	 * @param leyends	Leyends of each data group of the graph.
	 */
	public void setLeyends(Map leyends) {	this.leyends = leyends;		}

	/**
	 * @param leyendsPosition	The position of the leyends inside the graph.
	 */
	public void setLeyendsPosition(Integer leyendsPosition) {	this.leyendsPosition = leyendsPosition;		}

	/**
	 * @param barWidth	The width
	 */
	public void setBarWidth(Integer barWidth) {		this.barWidth = barWidth; 	}

	/**
	 * @param barsOfSameDataGroupSpacing	The bars spacing in pixels between bars of same data group in a horizontal/vertical bar chart.
	 */
	public void setBarsOfSameDataGroupSpacing(Integer barsOfSameDataGroupSpacing) {		this.barsOfSameDataGroupSpacing = barsOfSameDataGroupSpacing;	}

	/**
	 * @param barsOfDifferentDataGroupSpacing	The bars spacing in pixels between bars of different data group in a horizontal/vertical bar chart.
	 */
	public void setBarsOfDifferentDataGroupSpacing(Integer barsOfDifferentDataGroupSpacing) {	this.barsOfDifferentDataGroupSpacing = barsOfDifferentDataGroupSpacing;	}

	/**
	 * @param baseLinePosition	The position of the base line in a horizontal/vertical bar chart.
	 */
	public void setBaseLinePosition(Float baseLinePosition) {	this.baseLinePosition = baseLinePosition;	}

	/**
	 * @param lineWidth	   The width in pixels of the lines in a line chart.
	 */
	public void setLineWidth(Integer lineWidth) {	this.lineWidth = lineWidth;		}

	/**
	 * @param lineLength	The length in pixels of a line segment in a line chart.
	 */
	public void setLineLength(Integer lineLength) {		this.lineLength = lineLength;		}

	/**
	 * @param lineSpacing	The space in pixels between line segments in a line chart.
	 */
	public void setLineSpacing(Integer lineSpacing) {	this.lineSpacing = lineSpacing;		}

	/**
	 * @param gridCellHeight	The height of the grid's cells.
	 */
	public void setGridCellHeight(Integer gridCellHeight) {		this.gridCellHeight = gridCellHeight;	}

	/**
	 * @param gridCellWidth		The width of the grid's cells.
	 */
	public void setGridCellWidth(Integer gridCellWidth) {	this.gridCellWidth = gridCellWidth;		}

	/**
	 * @param gridLineLength	The lines length in pixels of the grid.
	 */
	public void setGridLineLength(Integer gridLineLength) {		this.gridLineLength = gridLineLength;	}

	/**
	 * @param gridLinesSpacing	The space in pixels between the lines of the grid.
	 */
	public void setGridLinesSpacing(Integer gridLinesSpacing) {		this.gridLinesSpacing = gridLinesSpacing;	}

	/**
	 * @param properties	A Collection with the properties that the chart will show.
	 */
	public void setProperties(Collection<ChartProperty> properties) {	this.properties = properties;	}

	/**
	 * @param dataTextEncoding	The data text encoding. It must be one of theese values:
	 * <p>	- Chart.CHART_PARAMETER_DATA_TEXT_ENCODING_VALUE_TEXT	</p>
	 * <p>	- Chart.CHART_PARAMETER_DATA_TEXT_ENCODING_VALUE_SIMPLE	</p>
	 * <p>	- Chart.CHART_PARAMETER_DATA_TEXT_ENCODING_VALUE_ENLARGED	</p>
	 */
	public void setDataTextEncoding(String dataTextEncoding) {	this.dataTextEncoding = dataTextEncoding;	}

	/**
	 * @param mapZone	The map zone to visualize on the chart. It must be one of theese values:
	 * <p>	- Chart.MAP_ZONE_AFRICA	</p>
	 * <p>	- Chart.MAP_ZONE_ASIA	</p>
	 * <p>	- Chart.MAP_ZONE_WORLD	</p>
	 * <p>	- Chart.MAP_ZONE_USA	</p>
	 * <p>	- Chart.MAP_ZONE_MIDDLE_EAST	</p>
	 * <p>	- Chart.MAP_ZONE_SOUTH_AMERICA	</p>
	 * <p>	- Chart.MAP_ZONE_EUROPE	</p>
	 */
	public void setMapZone(String mapZone) {	this.mapZone = mapZone;		}

}//  End Class
